package service

import (
	"context"
	"math/big"
	"reward-server/global"
	"reward-server/service/eth"
	"strings"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/spf13/cast"
	"go.uber.org/zap"
)

type ITokenService interface {
	TotalSupply() (int64, error)
	BalanceOf(addr string) (int64, error)
	TransferFrom(_to string, _value int64) (string, error)
	Approve(spender string, _value int64) (string, error)
}

type TokenService struct {
	Contract *eth.Token
}

func NewTokenService() ITokenService {

	//根据合约的地址加载合约
	cfg := global.ServerConfig.Eth
	contractAddress := common.HexToAddress(cfg.TokenAddr)
	contract, _ := eth.NewToken(contractAddress, global.Ethclient)

	return &TokenService{Contract: contract}
}

// TotalSupply 代币总数
func (t *TokenService) TotalSupply() (int64, error) {

	num, err := t.Contract.TotalSupply(new(bind.CallOpts))
	if err != nil {
		return 0, err

	}
	return cast.ToInt64(num), err
}

// 获取账户对应的代币余额
func (t *TokenService) BalanceOf(addr string) (int64, error) {

	account := common.HexToAddress(addr)
	num, err := t.Contract.BalanceOf(new(bind.CallOpts), account)
	if err != nil {
		return 0, err

	}
	return cast.ToInt64(num), err
}

// TransferFrom _from 为转账地址  _收款地址
func (t *TokenService) TransferFrom(_to string, _value int64) (string, error) {
	privateKeyStr := global.ServerConfig.Eth.PrivateKey
	privateKey, err := crypto.HexToECDSA(privateKeyStr)
	if err != nil {
		zap.S().Errorf("Invalid admin private key: %v", err)
		return "", err
	}

	// 2. 获取管理员地址
	adminAddress, err := GetAddressFromPrivateKey(privateKey)
	if err != nil {
		zap.S().Errorf("Failed to get admin address: %v", err)
		return "", err
	}

	// 3. 获取链 ID（如 Sepolia、Goerli 等）
	chainID, err := global.Ethclient.ChainID(context.Background())
	if err != nil {
		zap.S().Errorf("Failed to get chain ID: %v", err)
		return "", err
	}

	// 4. 创建 TransactOpts
	auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
	if err != nil {
		zap.S().Errorf("Failed to create transaction opts: %v", err)
		return "", err
	}
	auth.From = adminAddress

	// 5. 设置 Gas Limit（可选，如果不设置会自动估算）
	auth.GasLimit = 300000 // 根据合约操作复杂度适当调整

	// 6. 解析用户地址和收款地址
	// fromAddress := common.HexToAddress(_from)
	toAddress := common.HexToAddress(_to)

	// 7. 将 int64 的 _value 转换为 big.Int，并考虑代币小数位（假设为 18）
	value := big.NewInt(_value)
	value = value.Mul(value, big.NewInt(1e18)) // 假设代币有 18 位小数

	// 8. 调用智能合约的 transferFrom 方法
	tx, err := t.Contract.TransferFrom(auth, adminAddress, toAddress, value)
	if err != nil {
		zap.S().Errorf("Failed to invoke TransferFrom: %v", err)
		return "", err
	}

	// 9. 返回交易哈希供后续查询
	return tx.Hash().Hex(), nil

}

// Approve 用户授权管理员地址可操作其 `_value` 数量的代币
func (t *TokenService) Approve(spender string, _value int64) (string, error) {

	// 1. 获取用户私钥（从前端传入或通过签名服务获取）
	privateKey, err := crypto.HexToECDSA(strings.TrimPrefix(spender, "0x"))
	if err != nil {
		zap.S().Errorf("Invalid user private key: %v", err)
		return "", err
	}

	userAddress, err := GetAddressFromPrivateKey(privateKey)
	if err != nil {
		zap.S().Errorf("Failed to get user address: %v", err)
		return "", err
	}

	// 2. 获取链 ID
	chainID, err := global.Ethclient.ChainID(context.Background())
	if err != nil {
		zap.S().Errorf("Failed to get chain ID: %v", err)
		return "", err
	}

	// 3. 创建交易签名器
	auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
	if err != nil {
		zap.S().Errorf("Failed to create transaction opts: %v", err)
		return "", err
	}
	auth.From = userAddress

	// 4. 设置 Gas Limit（可选）
	auth.GasLimit = 500000

	// 5. 解析授权地址（管理员地址）
	adminPrivateKeyStr := global.ServerConfig.Eth.PrivateKey
	adminPrivateKey, err := crypto.HexToECDSA(adminPrivateKeyStr)
	if err != nil {
		zap.S().Errorf("Invalid admin private key: %v", err)
		return "", err
	}

	// 2. 获取管理员地址
	adminAddress, err := GetAddressFromPrivateKey(adminPrivateKey)
	if err != nil {
		zap.S().Errorf("Failed to get admin address: %v", err)
		return "", err
	}

	// 6. 转换金额（假设小数点为 18）
	value := new(big.Int).Mul(big.NewInt(int64(_value)), big.NewInt(1e18))

	// 7. 调用智能合约的 approve 方法
	tx, err := t.Contract.Approve(auth, adminAddress, value)
	if err != nil {
		zap.S().Errorf("Failed to invoke Approve: %v", err)
		return "", err
	}

	// 8. 返回交易哈希供后续查询
	return tx.Hash().Hex(), nil
}
